﻿using System;
using NLite.Reflection;
using NLite.Collections;
using NLite.Internal;
using NLite.Mini.Fluent;

namespace NLite
{
    /// <summary>
    /// 
    /// </summary>
    public static class FluentExtensions
    {

        private static void Register(IServiceRegistry kernel, Action<IBindingExpression> handler)
        {
            if (handler == null)
                throw new ArgumentNullException("handler == null");

            var component = new ComponentExpression { Registry = kernel };
            handler(component);

            InternalRegister(kernel, component);
        }

        private static void InternalRegister(IServiceRegistry kernel, ComponentExpression component)
        {
            if (component.Implementation == null && component.Factory == null)
                throw new ArgumentNullException("Implementation == null && Factory ==null");

            if (string.IsNullOrEmpty(component.Id))
            {
                if (component.Implementation != null)
                    component.Id = component.Implementation.FullName;
                else
                    component.Id = component.Factory.ToString() + "/" + component.Contracts[0].FullName;
            }

            if (component.Implementation != null && component.Implementation.IsOpenGenericType())
                component.Lifestyle = LifestyleType.GetGenericLifestyle(component.Lifestyle);

            kernel.Register(component);
        }

        private static void Register(IServiceRegistry kernel, Action<IComponentExpression> handler)
        {
            if (handler == null)
                throw new ArgumentNullException("handler == null");

            var component = new ComponentExpression { Registry = kernel };
            handler(component);

            InternalRegister(kernel, component);
        }


        /// <summary>
        /// 
        /// </summary>
        /// <param name="kernel"></param>
        /// <param name="handlers"></param>
        /// <returns></returns>
        public static IServiceRegistry Register(this IServiceRegistry kernel, params Action<IBindingExpression>[] handlers)
        {
            if (handlers != null && handlers.Length > 0)
                handlers.ForEach(exp => Register(kernel, exp));
            return kernel;
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="kernel"></param>
        /// <param name="handlers"></param>
        /// <returns></returns>
        public static IServiceRegistry Register(this IServiceRegistry kernel, params Action<IComponentExpression>[] handlers)
        {
            if (handlers != null && handlers.Length > 0)
                handlers.ForEach(exp => Register(kernel, exp));
            return kernel;
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="exp"></param>
        /// <returns></returns>
        public static IFactoryExpression Singleton(this IFactoryExpression exp)
        {
            return exp.Lifestyle(LifestyleFlags.Singleton);
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="exp"></param>
        /// <returns></returns>
        public static IComponentExpression Singleton(this IComponentExpression exp)
        {
            return exp.Lifestyle(LifestyleFlags.Singleton);
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="exp"></param>
        /// <returns></returns>
        public static IFactoryExpression Transient(this IFactoryExpression exp)
        {
            return exp.Lifestyle(LifestyleFlags.Transient);
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="exp"></param>
        /// <returns></returns>
        public static IComponentExpression Transient(this IComponentExpression exp)
        {
            return exp.Lifestyle(LifestyleFlags.Transient);
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="exp"></param>
        /// <returns></returns>
        public static IFactoryExpression Thread(this IFactoryExpression exp)
        {
            return exp.Lifestyle(LifestyleFlags.Thread);
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="exp"></param>
        /// <returns></returns>
        public static IComponentExpression Thread(this IComponentExpression exp)
        {
            return exp.Lifestyle(LifestyleFlags.Thread);
        }
    }
}
